// ------------------------------------------------------------------------------------------
// Licensed by Interprise Solutions.
// http://www.InterpriseSolutions.com
// For details on this license please visit  the product homepage at the URL above.
// THE ABOVE NOTICE MUST REMAIN INTACT.
// ------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Xml;
using System.IO;
using InterpriseSuiteEcommerceCommon.InterpriseIntegration.SqlQuery;


namespace InterpriseSuiteEcommerceCommon.InterpriseIntegration.Admin.QueryBrokers
{
    public class WidgetConfig : ICloneable 
    {
        private string _key = string.Empty;
        private string _path = string.Empty;
        private Type _brokerType;
        private WidgetConfig _filterWidget;
        private FilterConfig _filterConfig;

        private WidgetConfig() { }

        internal WidgetConfig(string key, string path) : this(key, path, null, null, null){}

        internal WidgetConfig(string key, string path, Type brokerType, WidgetConfig filterWidgetConfig, FilterConfig filterConfig)
        {
            _key = key;
            _path = path;
            _brokerType = brokerType;
            _filterWidget = filterWidgetConfig;
            _filterConfig = filterConfig;
        }

        public string Key
        {
            get { return _key; }
            set { _key = value; }
        }

        public string Path
        {
            get { return _path; }
            set { _path = value; }
        }

        public WidgetConfig FilterWidget
        {
            get { return _filterWidget; }
            set { _filterWidget = value; }
        }

        public FilterConfig FilterConfig
        {
            get { return _filterConfig; }
            set { _filterConfig = value; }
        }

        public IQueryBroker GetQueryBroker()
        {
            IQueryBroker broker = null;

            try
            {
                broker = Activator.CreateInstance(_brokerType) as IQueryBroker;
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return broker;
        }

        public object Clone()
        {
            return CloneWidget();
        }

        public WidgetConfig CloneWidget()
        {
            WidgetConfig clone = new WidgetConfig();
            clone.Key = _key;
            clone.Path = _path;
            clone._brokerType = _brokerType;
            return clone;
        }

    }

    public class WidgetFactory
    {
        private static WidgetFactory _factory = null;
        private static object _lock = new object();
        private const string CONFIG_FILE_PATH = "~/admin/widget.config";

        public static WidgetFactory Instance
        {
            get 
            {
                lock (_lock)
                {
                    if (null == _factory)
                    {
                        LoadAndConfigureWidgetConfig();
                    }

                    return _factory;
                }
            }
        }

        private Dictionary<string, WidgetConfig> _widgets = new Dictionary<string, WidgetConfig>();

        private Dictionary<string, WidgetConfig> Widgets
        {
            get { return _widgets; }
        }

        public WidgetConfig GetWidget(string key)
        {
            if (_widgets.ContainsKey(key))
            {
                return _widgets[key];
            }

            return null;
        }
     

        private void Configure(XmlDocument config)
        {
            // configure the brokers
            Dictionary<string, Type> _brokers = new Dictionary<string, Type>();
            XmlNodeList brokerNodes = config.SelectNodes("widget/brokers/add");
            foreach (XmlNode brokerNode in brokerNodes)
            {
                string key      = GetAttributeValue(brokerNode, "key");
                string typeName = GetAttributeValue(brokerNode, "type");

                if (!_brokers.ContainsKey(key))
                {
                    Type brokerType = Type.GetType(typeName);
                    if (null == brokerType)
                    {
                        throw new ArgumentException("Broker Type cannot be loaded!!!", typeName);
                    }

                    _brokers.Add(key, Type.GetType(typeName));
                }
            }

            // configure the filter widgets
            Dictionary<string, WidgetConfig> filterWidgets = new Dictionary<string, WidgetConfig>();
            XmlNodeList filterWidgetNodes = config.SelectNodes("widget/widgets/filters/add");
            foreach (XmlNode filterWidgetNode in filterWidgetNodes)
            {
                string key = GetAttributeValue(filterWidgetNode, "key");
                string path = GetAttributeValue(filterWidgetNode, "path");
                if (!filterWidgets.ContainsKey(key))
                {
                    WidgetConfig filterWidgetConfig = new WidgetConfig(key, path);
                    filterWidgets.Add(key, filterWidgetConfig);
                }
            }

            // configure the model widgets
            XmlNodeList modelWidgetNodes = config.SelectNodes("widget/widgets/models/add");
            foreach (XmlNode modelWidgetNode in modelWidgetNodes)
            {
                WidgetConfig filterWidget = null;

                // check if we have a filter node
                XmlNode modelWidgetFilterNode = modelWidgetNode.SelectSingleNode("filter");
                if (null != modelWidgetFilterNode)
                {
                    string filterWidgetKey = GetAttributeValue(modelWidgetFilterNode, "widget");
                    if (filterWidgets.ContainsKey(filterWidgetKey))
                    {
                        WidgetConfig filterWidgetConfig = filterWidgets[filterWidgetKey];
                        if (null != filterWidgetConfig)
                        {
                            filterWidget = filterWidgetConfig.CloneWidget();
                            FilterConfig filterConfig = new FilterConfig();                            

                            bool showDateFilter = bool.TryParse(GetAttributeValue(modelWidgetFilterNode, "showDate"), out showDateFilter) && showDateFilter;
                            string dateColumn   = GetAttributeValue(modelWidgetFilterNode, "dateColumn");

                            filterConfig.ShowDate = showDateFilter;
                            if(filterConfig.ShowDate)
                            {
                                if (string.IsNullOrEmpty(dateColumn))
                                {
                                    throw new ArgumentException("Date column for filter not specified!!!");
                                }
                                else
                                {
                                    filterConfig.DateColumn = dateColumn;
                                }
                            }

                            filterWidget.FilterConfig = filterConfig;
                        }
                    }
                }

                string widgetKey    = GetAttributeValue(modelWidgetNode, "key");
                string widgetPath   = GetAttributeValue(modelWidgetNode, "path");
                string brokerKey    = GetAttributeValue(modelWidgetNode, "broker");
                
                if(!_widgets.ContainsKey(widgetKey))
                {
                    if (!_brokers.ContainsKey(brokerKey))
                    {
                        throw new ArgumentException("Broker not found!!!", brokerKey);
                    }

                    Type brokerType = _brokers[brokerKey];

                    // now configure the model widget
                    WidgetConfig modelWidget = new WidgetConfig(widgetKey, widgetPath, brokerType, filterWidget, null);

                    // add to the collection
                    _widgets.Add(widgetKey, modelWidget);
                }
            }
        }

        private string GetAttributeValue(XmlNode node, string name)
        {
            if (null == node.Attributes[name]) throw new ArgumentException("Attribute missing", name);
            return node.Attributes[name].Value;
        }

        private static void LoadAndConfigureWidgetConfig()
        {
            try
            {
                _factory = new WidgetFactory();

                XmlDocument doc = new XmlDocument();
                string configPath = HttpContext.Current.Server.MapPath(CONFIG_FILE_PATH);
                using (FileStream brokerConfigStream = new FileStream(configPath, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    doc.Load(brokerConfigStream);
                }

                _factory.Configure(doc);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}
